import os
from common.settings import logger
import requests
from typing import Union
from common.constant import RequestType, ApiInfo, UploadApiField, ParamsType, RequestHandlerErrorInfo, ExcelHead
from utils.otherUtils.file_control import check_file_path


class RequestHandler:

    def __init__(self, api_info: dict):
        self.api_info = api_info

    @property
    def api_describe(self) -> Union[str, None]:
        return self.api_info.get(ApiInfo.DESCRIBE.value)

    @property
    def api_request_type(self) -> Union[str, None]:
        return self.api_info.get(ApiInfo.REQUEST_TYPE.value)

    @property
    def api_host(self) -> Union[str, None]:
        return self.api_info.get(ApiInfo.HOST.value)

    @property
    def api_url(self) -> Union[str, None]:
        return self.api_info.get(ApiInfo.URL.value)

    @property
    def api_method(self) -> Union[str, None]:
        return self.api_info.get(ApiInfo.METHOD.value)

    @property
    def api_headers(self) -> Union[dict, None]:
        return self.api_info.get(ApiInfo.HEADERS.value)

    def check_api_info(self) -> None:
        if not self.api_request_type:
            logger.error(RequestHandlerErrorInfo.REQUEST_TYPE_IS_NONE.value)
            raise ValueError(RequestHandlerErrorInfo.REQUEST_TYPE_IS_NONE.value)
        if not self.api_host:
            logger.error(RequestHandlerErrorInfo.HOST_IS_NONE.value)
            raise ValueError(RequestHandlerErrorInfo.HOST_IS_NONE.value)
        if not self.api_url:
            logger.error(RequestHandlerErrorInfo.URL_IS_NONE.value)
            raise ValueError(RequestHandlerErrorInfo.URL_IS_NONE.value)
        if not self.api_method:
            logger.error(RequestHandlerErrorInfo.METHOD_IS_NONE.value)
            raise ValueError(RequestHandlerErrorInfo.METHOD_IS_NONE.value)
        if not self.api_headers:
            logger.error(RequestHandlerErrorInfo.HEADERS_IS_NONE.value)
            raise ValueError(RequestHandlerErrorInfo.HEADERS_IS_NONE.value)

    @staticmethod
    def float_to_int(payload: dict) -> None:
        #  将小数位是0的浮点数转换为整数，如：将1.0转换为1
        for key, value in payload.items():
            if isinstance(value, float):
                if value - int(value) == 0:
                    payload[key] = int(value)

    def three_types_request(self, payload: dict, data_info: dict, file_path: str) -> str:
        case_info = f'\n用例序号：{data_info[ExcelHead.ID.value]}，用例说明：{data_info[ExcelHead.DESCRIBE.value]}，' \
                    f'用例作者：{data_info[ExcelHead.AUTHOR.value]}，用例文件：{file_path}\n' \
                    f'接口描述：{self.api_describe}\n' \
                    f'接口url：{self.api_host + self.api_url}\n' \
                    f'接口headers：{self.api_headers}\n' \
                    f'请求类型：{self.api_request_type}\n' \
                    f'请求参数：{payload}\n'
        self.float_to_int(payload)
        try:
            if self.api_request_type == RequestType.QUERY_STRING.value:
                response = requests.request(method=self.api_method, url=self.api_host + self.api_url,
                                            headers=self.api_headers, params=payload)
            elif self.api_request_type == RequestType.FORM.value:
                response = requests.request(method=self.api_method, url=self.api_host + self.api_url,
                                            headers=self.api_headers, data=payload)
            elif self.api_request_type == RequestType.JSON.value:
                response = requests.request(method=self.api_method, url=self.api_host + self.api_url,
                                            headers=self.api_headers, json=payload)
            else:
                logger.error(RequestHandlerErrorInfo.REQUEST_TYPE_IS_WRONG.value)
                raise ValueError(RequestHandlerErrorInfo.REQUEST_TYPE_IS_WRONG.value)
            logger.info(f'{case_info}接口响应结果：{response.text}')
            return response.text
        except Exception as e:
            logger.error(e)

    def file_type_request(self, payload: dict, data_info: dict, file_path: str, upload_info: dict) -> str:
        upload_file_path = upload_info.get(UploadApiField.FILE_PATH.value)
        upload_file_path = check_file_path(upload_file_path)
        upload_file_name = os.path.basename(upload_file_path)
        upload_file_type = upload_info.get(UploadApiField.FILE_TYPE.value)
        upload_params_type = upload_info.get(UploadApiField.PARAMS_TYPE.value)

        case_info = f'\n用例序号：{data_info[ExcelHead.ID.value]}，用例说明：{data_info[ExcelHead.DESCRIBE.value]}，' \
                    f'用例作者：{data_info[ExcelHead.AUTHOR.value]}，用例文件：{file_path}\n' \
                    f'接口描述：{self.api_describe}\n' \
                    f'接口url：{self.api_host + self.api_url}\n' \
                    f'接口headers：{self.api_headers}\n' \
                    f'请求类型：{self.api_request_type}\n' \
                    f'请求参数：{payload}\n' \
                    f'上传文件的路径：{upload_file_path}\n'

        # 需要传其它参数
        if upload_params_type:
            try:
                with open(upload_file_path, 'rb') as file:
                    files = {'upload_file': (upload_file_name, file, upload_file_type)}
                    self.float_to_int(payload)
                    # 除了上传文件，还需要传查询字符串
                    if upload_params_type == ParamsType.PATH_PARAMS.value:
                        response = requests.request(method=self.api_method, url=self.api_host + self.api_url,
                                                    headers=self.api_headers, params=payload, files=files)
                    # 除了上传文件，还需要传表单
                    elif upload_params_type == ParamsType.FORM.value:
                        response = requests.request(method=self.api_method, url=self.api_host + self.api_url,
                                                    headers=self.api_headers, data=payload, files=files)
                    # 除了上传文件，还需要传json
                    elif upload_params_type == ParamsType.JSON.value:
                        response = requests.request(method=self.api_method, url=self.api_host + self.api_url,
                                                    headers=self.api_headers, json=payload, files=files)
                    else:
                        logger.error(RequestHandlerErrorInfo.REQUEST_TYPE_IS_WRONG.value)
                        raise ValueError(RequestHandlerErrorInfo.REQUEST_TYPE_IS_WRONG.value)
                    logger.info(f'{case_info}接口响应结果：{response.text}')
                    return response.text
            except Exception as e:
                logger.error(e)
        # 不需要传其它参数
        else:
            try:
                with open(upload_file_path, 'rb') as file:
                    files = {'upload_file': (upload_file_name, file, upload_file_type)}
                    response = requests.request(method=self.api_method, url=self.api_host + self.api_url,
                                                headers=self.api_headers, files=files)
                    logger.info(f'{case_info}接口响应结果：{response.text}')
                    return response.text
            except Exception as e:
                logger.error(e)

    def run(self, payload: dict, data_info: dict, file_path: str, upload_info: dict = None) -> str:
        if self.api_request_type == RequestType.FILE.value:
            return self.file_type_request(payload, data_info, file_path, upload_info)
        else:
            return self.three_types_request(payload, data_info, file_path)
